home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 1995 #5 & #6 / Amiga Plus CD - 1995 - No. 5 and 6.iso / pd / netz / amyboard / amiga / childio.c < prev    next >
C/C++ Source or Header  |  1995-08-12  |  32KB  |  1,317 lines

  1. /**
  2. ***  childio.c  -- Internal pipe for child process communications
  3. ***
  4. *** ------------------------------------------------------------------------
  5. ***  This program is free software; you can redistribute it and/or modify
  6. ***  it under the terms of the GNU General Public License as published by
  7. ***  the Free Software Foundation; either version 2 of the License, or
  8. ***  (at your option) any later version.
  9. ***
  10. ***  This program is distributed in the hope that it will be useful,
  11. ***  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. ***  GNU General Public License for more details.
  14. ***
  15. ***  You should have received a copy of the GNU General Public License
  16. ***  along with this program; if not, write to the Free Software
  17. ***  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18. *** ------------------------------------------------------------------------
  19. ***
  20. ***
  21. ***  Process communication is done using a second Process, which acts as a
  22. ***  handler. It would be possible to manage everything with one process,
  23. ***  but the increase of speed is not that much and it simplifies things.
  24. ***  It would as well be possible to use a separate pipe handler, but there
  25. ***  are a few problems:
  26. ***
  27. ***  - Usual pipes ("PIPE:" for example) don't work interactively. The
  28. ***    reading process has to wait until the writing process closes the
  29. ***    file.
  30. ***  - The first point could be solved by writing an own handler which
  31. ***    would do quite the same as our internal handler. But we would
  32. ***    need a MountList entry and it would not be possible to remove
  33. ***    this handler.
  34. ***
  35. ***  I recommend chapter 21 of Ralph Babel's "Guru book" for a complete
  36. ***  understanding of what's going on here. (And, BTW, thanks, Ralph,
  37. ***  for your explanations at IRC!)
  38. **/
  39.  
  40.  
  41.  
  42.  
  43.  
  44. /***  Includes section
  45. */
  46. #include "amyboard.h"
  47.  
  48. #include <ctype.h>
  49. #include <fcntl.h>
  50.  
  51. #include <exec/memory.h>
  52. #include <dos/dosextens.h>
  53. #include <dos/dostags.h>
  54. #include <rexx/rexxio.h>
  55.  
  56. #if defined(__GNUC__)
  57. extern BPTR *__stdfiledes;
  58. #define fdtofh(a) (__stdfiledes[a])
  59. #endif
  60. /**/
  61.  
  62.  
  63.  
  64.  
  65. /*** Type definitions
  66. */
  67. typedef struct              /*  Our private extension of the MinNode    */
  68. { struct Node *succ;
  69.   struct Node *pred;
  70.   ULONG size;
  71. } MyMinNode;
  72.  
  73. typedef struct              /*  This structure is created for every     */
  74. { MyMinNode node;           /*  filehandle that is waiting for input,   */
  75.   struct DosPacket *dp;     /*  if no input is available yet.           */
  76. } ReadRequest;
  77.  
  78. typedef struct              /*  This structure is created, if a filehandle  */
  79. { MyMinNode node;           /*  wants to write output, but the ReadRequests */
  80.   ULONG numBytes;           /*  available aren't sufficient. numBytes is    */
  81.   ULONG written;            /*  the available number of bytes, written      */
  82.   UBYTE *buffer;            /*  is the number of bytes already written.     */
  83. } WriteRequest;
  84.  
  85. typedef struct              /*  A pointer to this structure is stored in    */
  86. { APTR pipe;                /*  the fh_Arg1 entry of the filehandle.        */
  87. } XBoardFileHandle;
  88.  
  89. typedef struct              /*  This structure implements one pipe.         */
  90. { MyMinNode node;           /*  Note, that always almost one of the two     */
  91.   struct MinList rreqList;  /*  lists is empty.                             */
  92.   struct MinList wreqList;
  93.   XBoardFileHandle *readFH;
  94.   XBoardFileHandle *writeFH;
  95. } XBoardPipe;
  96.  
  97. /**/
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104. /***  Macro section
  105. */
  106. #define RemoveMyMinNode(mmn) \
  107.   { Remove((struct Node *)mmn); \
  108.     LibFreePooled(pipesPool, mmn, (mmn)->size); \
  109.   }
  110. #define CreateMyMinNode(len) LibAllocPooled(pipesPool, (len))
  111. /**/
  112.  
  113.  
  114.  
  115.  
  116. /*** Variable section
  117. */
  118. struct Process *handlerProcess  = NULL;
  119. struct MsgPort *pipesPort       = NULL;
  120. struct DosPacket *pipesPacket   = NULL;
  121. APTR pipesPool                  = NULL;
  122. ULONG pipeSignals;
  123. struct MinList inputSourceList;
  124. struct MinList childProcessList;
  125. /**/
  126.  
  127.  
  128.  
  129.  
  130. /*** xboardPipesHandler function
  131. ***
  132. ***  This is the equivalent to the handlers main. It is
  133. ***  the entry point of the second process and called via
  134. **   CreateNewProc().
  135. **/
  136. #ifdef DEBUG_HANDLER
  137. void kprints(char *buffer, int len)
  138.  
  139. { int i;
  140.  
  141.   kprintf("(%ld bytes, ", len);
  142.   for (i = len;  i;  i--)
  143.   { char c = *buffer++;
  144.  
  145.     switch(c)
  146.     { case '\n':
  147.     kprintf("\\n");
  148.     break;
  149.       case '\0':
  150.     kprintf("\\0");
  151.     break;
  152.       case '\t':
  153.     kprintf("\\t");
  154.     break;
  155.       case '\r':
  156.     kprintf("\\r");
  157.     break;
  158.       default:
  159.     kprintf("%lc", c);
  160.     }
  161.   }
  162.   kprintf(")\n");
  163. }
  164. #endif
  165. extern VOID xboardPipesHandler(VOID);
  166. _SAVEDS_FUNC(VOID, xboardPipesHandler) (VOID)
  167.  
  168. { struct MsgPort *messagePort;
  169.   struct DosPacket *dosPacket;
  170.   struct DosPacket *diePacket = NULL;
  171.   struct MinList xboardPipesList; /*  List of open pipes.             */
  172.   struct Message *currentMessage;
  173.  
  174.   messagePort = &((struct Process *) FindTask(NULL))->pr_MsgPort;
  175.   NewList((struct List *) &xboardPipesList);
  176.  
  177.   /**
  178.   ***  Never ending loop to process the incoming packets.
  179.   **/
  180.   for (;;)
  181.   { WaitPort(messagePort);
  182.     while((currentMessage = GetMsg(messagePort)))
  183.     { dosPacket = (struct DosPacket *) currentMessage->mn_Node.ln_Name;
  184.       switch(dosPacket->dp_Type)
  185.       { case ACTION_FINDINPUT:
  186.     case ACTION_FINDOUTPUT:
  187.     case ACTION_FINDUPDATE:
  188.     { XBoardPipe *xp;
  189.       XBoardFileHandle *xfh;
  190.       struct FileHandle *fh;
  191.  
  192.       /**
  193.       ***  Create a FileHandle.
  194.       **/
  195.       if ((xfh = CreateMyMinNode(sizeof(*xfh)))  ==  NULL)
  196.       { ReplyPkt(dosPacket, DOSFALSE, ERROR_NO_FREE_STORE);
  197. #ifdef DEBUG_HANDLER
  198. #define kprinta(type)                         \
  199.         switch(type)                      \
  200.         { case ACTION_FINDINPUT:          \
  201.         kprintf("ACTION_FINDINPUT");  \
  202.         break;                        \
  203.           case ACTION_FINDOUTPUT:         \
  204.         kprintf("ACTION_FINDOUTPUT"); \
  205.         break;                        \
  206.           case ACTION_FINDUPDATE:         \
  207.         kprintf("ACTION_FINDUPDATE"); \
  208.         break;                        \
  209.         }
  210.         kprintf("Handler: ");
  211.         kprinta(dosPacket->dp_Type);
  212.         kprintf(" failed, memory error");
  213. #endif
  214.         break;
  215.       }
  216.  
  217.       if (dosPacket->dp_Type == ACTION_FINDINPUT)
  218.       { /**
  219.         ***  If it is a read filehandle: Connect it to the last opened
  220.         ***  pipe. This would not make much sense in a public handler,
  221.         ***  but works fine for us.
  222.         **/
  223.         xp = (XBoardPipe *) xboardPipesList.mlh_TailPred;
  224.         xp->readFH = xfh;
  225.       }
  226.       else
  227.       { /**
  228.         ***  If it is a writing filehandle: Create a new pipe.
  229.         **/
  230.         if ((xp = CreateMyMinNode(sizeof(*xp)))  ==  NULL)
  231.         { ReplyPkt(dosPacket, DOSFALSE, ERROR_NO_FREE_STORE);
  232.           LibFreePooled(pipesPool, xfh, sizeof(*xfh));
  233. #ifdef DEBUG_HANDLER
  234.           kprintf("Handler: ");
  235.           kprinta(dosPacket->dp_Type);
  236.           kprintf(" failed, memory error");
  237. #endif
  238.           break;
  239.         }
  240.         xp->node.size = sizeof(*xp);
  241.         xp->writeFH = xfh;
  242.         xp->readFH = NULL;
  243.         AddTail((struct List *) &xboardPipesList, (struct Node *) xp);
  244.         NewList((struct List *) &xp->rreqList);
  245.         NewList((struct List *) &xp->wreqList);
  246.       }
  247.  
  248.       xfh->pipe = xp;
  249.       fh = (struct FileHandle *) BADDR(dosPacket->dp_Arg1);
  250.       fh->fh_Arg1 = (LONG) xfh;
  251.       fh->fh_Port = (struct MsgPort *) DOSTRUE;
  252.       if (dosPacket->dp_Type == ACTION_FINDUPDATE)
  253.       { fh->fh_Type = pipesPort;    /*  Packets will be sent to the */
  254.       }                             /*  XBoard process immediately. */
  255.  
  256.       ReplyPkt(dosPacket, DOSTRUE, 0);
  257.  
  258. #ifdef DEBUG_HANDLER
  259.       kprintf("Handler: ");
  260.       kprinta(dosPacket->dp_Type);
  261.       kprintf(": Pipe %08lx, FileHandle %08lx created.\n",
  262.           xp, xfh);
  263. #endif
  264.       break;
  265.     }
  266.     case ACTION_READ:
  267.     { XBoardPipe *xp;
  268.       XBoardFileHandle *xfh;
  269.       WriteRequest *wreq;
  270.       ReadRequest *rreq;
  271.  
  272.       xfh = (XBoardFileHandle *) dosPacket->dp_Arg1;
  273.       xp = xfh->pipe;
  274.  
  275.       /**
  276.       ***  Fail, if this is not the reading filehandle.
  277.       **/
  278.       if (xfh  !=  xp->readFH)
  279.       {
  280. #ifdef DEBUG_HANDLER
  281.         kprintf("Handler: ACTION_READ, Pipe %08lx, FileHandle %08lx:\n"
  282.             "         Not reading filehandle, failed.\n",
  283.             xp, xfh);
  284. #endif
  285.         ReplyPkt(dosPacket, 0, ERROR_OBJECT_WRONG_TYPE);
  286.         break;
  287.       }
  288.  
  289.       /**
  290.       ***  Check, if a WriteRequest is waiting.
  291.       **/
  292.       wreq = (WriteRequest *) xp->wreqList.mlh_Head;
  293.       if (wreq->node.succ)
  294.       { ULONG bytesToWrite;
  295.  
  296.         bytesToWrite = MIN(wreq->numBytes - wreq->written,
  297.                    dosPacket->dp_Arg3);
  298.         CopyMem(wreq->buffer + wreq->written,
  299.             (void *) dosPacket->dp_Arg2,
  300.             bytesToWrite);
  301. #ifdef DEBUG_HANDLER
  302.         kprintf("Handler: ACTION_READ, Pipe %08lx, FileHandle %08lx:\n"
  303.             "         Wrote from write request %08lx ",
  304.             xp, xfh, wreq);
  305.         kprints((char *) dosPacket->dp_Arg2, bytesToWrite);
  306. #endif
  307.         ReplyPkt(dosPacket, bytesToWrite, 0);
  308.         wreq->written += bytesToWrite;
  309.  
  310.         if (wreq->written  ==  wreq->numBytes)
  311.         { RemoveMyMinNode((MyMinNode *) wreq);
  312.         }
  313.         break;
  314.       }
  315.  
  316.  
  317.       /**
  318.       ***  Return EOF, if the writing filehandle is closed.
  319.       **/
  320.       if (!xp->writeFH)
  321.       {
  322. #ifdef DEBUG_HANDLER
  323.         kprintf("Handler: ACTION_READ, Pipe %08lx, FileHandle %08lx:\n"
  324.             "         Sent EOF.\n",
  325.             xp, xfh);
  326. #endif
  327.         ReplyPkt(dosPacket, 0, 0);
  328.         break;
  329.       }
  330.  
  331.       /**
  332.       ***  Otherwise create a ReadRequest.
  333.       **/
  334.       if ((rreq = CreateMyMinNode(sizeof(*rreq)))  ==  NULL)
  335.       {
  336. #ifdef DEBUG_HANDLER
  337.         kprintf("Handler: ACTION_READ, Pipe %08lx, FileHandle %08lx:\n"
  338.             "         Failed to create read request, memory error.\n",
  339.             xp, xfh);
  340. #endif
  341.         ReplyPkt(dosPacket, 0, ERROR_NO_FREE_STORE);
  342.         break;
  343.       }
  344.       rreq->node.size = sizeof(*rreq);
  345.       rreq->dp = dosPacket;
  346.       AddTail((struct List *) &xp->rreqList, (struct Node *) rreq);
  347. #ifdef DEBUG_HANDLER
  348.       kprintf("Handler: ACTION_READ, Pipe %08lx, FileHandle %08lx:\n"
  349.           "         Created read request %08lx.\n",
  350.           xp, xfh, rreq);
  351. #endif
  352.       break;
  353.     }
  354.     case ACTION_WRITE:
  355.     { XBoardPipe *xp;
  356.       XBoardFileHandle *xfh;
  357.       ReadRequest *rreq;
  358.       ULONG written = 0;
  359.       ULONG toWrite;
  360.  
  361.       xfh = ((XBoardFileHandle *) dosPacket->dp_Arg1);
  362.       xp = xfh->pipe;
  363.       toWrite = dosPacket->dp_Arg3;
  364.  
  365.       /**
  366.       ***  Fail, if this is not the writing filehandle.
  367.       **/
  368.       if (dosPacket->dp_Arg1  !=  (LONG) xp->writeFH)
  369.       {
  370. #ifdef DEBUG_HANDLER
  371.         kprintf("Handler: ACTION_WRITE, Pipe %08lx, FileHandle %08lx:\n"
  372.             "         Not writing filehandle, failed.\n",
  373.             xp, xfh);
  374. #endif
  375.         ReplyPkt(dosPacket, 0, ERROR_OBJECT_WRONG_TYPE);
  376.         break;
  377.       }
  378.  
  379.       /**
  380.       ***  Fail, if the reading filehandle is closed.
  381.       **/
  382.       if (!xp->readFH)
  383.       {
  384. #ifdef DEBUG_HANDLER
  385.         kprintf("Handler: ACTION_WRITE, Pipe %08lx, FileHandle %08lx:\n"
  386.             "         Reading filehandle closed, failed.\n",
  387.             xp, xfh);
  388. #endif
  389.         ReplyPkt(dosPacket, 0, ERROR_OBJECT_NOT_FOUND);
  390.         break;
  391.       }
  392.  
  393.       /**
  394.       ***  Check, if ReadRequests are waiting.
  395.       **/
  396.       while (toWrite > 0  &&
  397.          (rreq = (ReadRequest *) xp->rreqList.mlh_Head)->node.succ)
  398.       { ULONG bytesToWrite;
  399.  
  400.         bytesToWrite = MIN(toWrite, rreq->dp->dp_Arg3);
  401.         CopyMem((STRPTR) dosPacket->dp_Arg2 + written,
  402.             (STRPTR) rreq->dp->dp_Arg2,
  403.             bytesToWrite);
  404.  
  405. #ifdef DEBUG_HANDLER
  406.         kprintf("Handler: ACTION_WRITE, Pipe %08lx, FileHandle %08lx:\n"
  407.             "         Wrote to read request %08lx ",
  408.             xp, xfh, rreq);
  409.         kprints((STRPTR) rreq->dp->dp_Arg2, bytesToWrite);
  410. #endif
  411.         ReplyPkt(rreq->dp, bytesToWrite, 0);
  412.         written += bytesToWrite;
  413.         toWrite -= bytesToWrite;
  414.         RemoveMyMinNode((MyMinNode *) rreq);
  415.       }
  416.  
  417.       /**
  418.       ***   If bytes are still remaining: Create a write request.
  419.       **/
  420.       if (toWrite > 0)
  421.       { WriteRequest *wreq;
  422.  
  423.         if (!(wreq = CreateMyMinNode(sizeof(*wreq) + toWrite)))
  424.         {
  425. #ifdef DEBUG_HANDLER
  426.         kprintf("Handler: ACTION_WRITE, Pipe %08lx, FileHandle %08lx:\n"
  427.             "         Failed to create write request, memory error.\n",
  428.             xp, xfh);
  429. #endif
  430.           ReplyPkt(dosPacket, written, ERROR_NO_FREE_STORE);
  431.           break;
  432.         }
  433.         wreq->node.size = sizeof(*wreq) + toWrite;
  434.         wreq->numBytes = toWrite;
  435.         wreq->buffer = ((UBYTE *) wreq) + sizeof(*wreq);
  436.         wreq->written = 0;
  437.         CopyMem((UBYTE *) dosPacket->dp_Arg2 + written,
  438.             wreq->buffer,
  439.             toWrite);
  440.         AddTail((struct List *) &xp->wreqList, (struct Node *) wreq);
  441. #ifdef DEBUG_HANDLER
  442.         kprintf("Handler: ACTION_WRITE, Pipe %08lx, FileHandle %08lx:\n"
  443.             "         Create write request %08lx ",
  444.             xp, xfh, wreq);
  445.         kprints(wreq->buffer, toWrite);
  446.         kprintf("         write request List:\n");
  447.         { WriteRequest *wreq;
  448.           for (wreq = (WriteRequest *) xp->wreqList.mlh_Head;
  449.            wreq->node.succ;
  450.            wreq = (WriteRequest *) wreq->node.succ)
  451.           { kprintf("        %08lx ");
  452.         kprints(wreq->buffer+wreq->written, wreq->numBytes-wreq->written);
  453.           }
  454.         }
  455. #endif
  456.       }
  457.  
  458.       ReplyPkt(dosPacket, dosPacket->dp_Arg3, 0);
  459.       break;
  460.     }
  461.     case ACTION_WAIT_CHAR:
  462.     { XBoardPipe *xp;
  463.       XBoardFileHandle *xfh;
  464.       WriteRequest *wreq;
  465.  
  466.       xfh = (XBoardFileHandle *) dosPacket->dp_Arg2;
  467.       xp = xfh->pipe;
  468.  
  469.       /**
  470.       ***  Fail, if this is not the reading filehandle.
  471.       **/
  472.       if (xfh  !=  xp->readFH)
  473.       {
  474. #ifdef DEBUG_HANDLER
  475.         kprintf("Handler: ACTION_WAIT_CHAR, Pipe %08lx, FileHandle %08lx:\n"
  476.             "         Not reading filehandle, failed.\n",
  477.             xp, xfh);
  478. #endif
  479.         ReplyPkt(dosPacket, 0, ERROR_OBJECT_WRONG_TYPE);
  480.         break;
  481.       }
  482.  
  483.       /**
  484.       ***  Fail, if the timeout argument is nonzero.
  485.       **/
  486.       if (dosPacket->dp_Arg1)
  487.       {
  488. #ifdef DEBUG_HANDLER
  489.         kprintf("Handler: ACTION_WAIT_CHAR, Pipe %08lx, FileHandle %08lx:\n"
  490.             "         Nonzero timeout argument, failed.\n",
  491.             xp, xfh);
  492. #endif
  493.         ReplyPkt(dosPacket, 0, ERROR_ACTION_NOT_KNOWN);
  494.         break;
  495.       }
  496.  
  497.       /**
  498.       ***  Check, if a WriteRequest is waiting.
  499.       **/
  500.       wreq = (WriteRequest *) xp->wreqList.mlh_Head;
  501. #ifdef DEBUG_HANDLER
  502.       kprintf("Handler: ACTION_WAIT_CHAR, Pipe %08lx, FileHandle %08lx:\n"
  503.           "         Returning %s.\n",
  504.           xp, xfh, wreq->node.succ ? "DOSTRUE" : "DOSFALSE");
  505. #endif
  506.       ReplyPkt(dosPacket, wreq->node.succ ? DOSTRUE : DOSFALSE, 0);
  507.       break;
  508.     }
  509.     case ACTION_END:
  510.     { XBoardPipe *xp;
  511.       XBoardFileHandle *xfh;
  512.  
  513.  
  514.       xfh = (XBoardFileHandle *) dosPacket->dp_Arg1;
  515.       xp = xfh->pipe;
  516.  
  517.       /**
  518.       ***  If this is the writing filehandle: Send EOF to the reading
  519.       ***  filehandle.
  520.       **/
  521.       if (xfh == xp->writeFH)
  522.       { ReadRequest *rreq;
  523.  
  524.         xp->writeFH = NULL;
  525.         while ((rreq = (ReadRequest *) xp->rreqList.mlh_Head)->node.succ)
  526.         { ReplyPkt(rreq->dp, 0, 0);
  527.           RemoveMyMinNode((MyMinNode *) rreq);
  528.         }
  529.       }
  530.       /**
  531.       ***  If it is the reading filehandle: Remove any write requests.
  532.       **/
  533.       else
  534.       { WriteRequest *wreq;
  535.  
  536.         xp->readFH = NULL;
  537.         while((wreq = (WriteRequest *) xp->wreqList.mlh_Head)->node.succ)
  538.         { RemoveMyMinNode((MyMinNode *) wreq);
  539.         }
  540.       }
  541. #ifdef DEBUG_HANDLER
  542.       kprintf("Handler: ACTION_END, Pipe %08lx, FileHandle %08lx.\n",
  543.           xp, xfh);
  544. #endif
  545.       LibFreePooled(pipesPool, xfh, sizeof(*xfh));
  546.  
  547.       if (!xp->writeFH  &&  !xp->readFH)
  548.       { RemoveMyMinNode((MyMinNode *) xp);
  549.       }
  550.  
  551.       ReplyPkt(dosPacket, DOSTRUE, 0);
  552.  
  553.       if (!diePacket)
  554.       { break;
  555.       }
  556.     }
  557.     case ACTION_DIE:
  558.       if (!diePacket)
  559.       { diePacket = dosPacket;
  560.       }
  561.       if (!xboardPipesList.mlh_Head->mln_Succ)
  562.       { ReplyPkt(diePacket, DOSTRUE, 0);
  563.         CloseLibrary((struct Library *) DOSBase);
  564. #ifdef DEBUG_HANDLER
  565.         kprintf("Handler: Terminating.\n");
  566. #endif
  567.         return;
  568.       }
  569.       break;
  570.     case ACTION_IS_FILESYSTEM:
  571. #ifdef DEBUG_HANDLER
  572.       kprintf("Handler: ACTION_IS_FILESYSTEM.\n");
  573. #endif
  574.       ReplyPkt(dosPacket, DOSFALSE, 0);
  575.       break;
  576.     case ACTION_SEEK:
  577. #ifdef DEBUG_HANDLER
  578.       kprintf("Handler: ACTION_SEEK.\n");
  579. #endif
  580.       ReplyPkt(dosPacket, -1, ERROR_ACTION_NOT_KNOWN);
  581.       break;
  582.     case ACTION_SET_FILE_SIZE:
  583. #ifdef DEBUG_HANDLER
  584.       kprintf("Handler: ACTION_SET_FILE_SIZE.\n");
  585. #endif
  586.       ReplyPkt(dosPacket, -1, ERROR_ACTION_NOT_KNOWN);
  587.       break;
  588.     default:
  589. #ifdef DEBUG_HANDLER
  590.       kprintf("Handler: Action %ld.\n", dosPacket->dp_Type);
  591. #endif
  592.       ReplyPkt(dosPacket, DOSFALSE, ERROR_ACTION_NOT_KNOWN);
  593.       break;
  594.       }
  595.     }
  596.   }
  597. }
  598. /**/
  599.  
  600.  
  601.  
  602.  
  603.  
  604. /*** pipeClose function
  605. ***
  606. ***  Close() replacement
  607. **/
  608. BOOL pipeClose(BPTR file)
  609.  
  610. { struct FileHandle *fh;
  611.  
  612.   if (file)
  613.   { fh = (struct FileHandle *) BADDR(file);
  614.     fh->fh_Type = &handlerProcess->pr_MsgPort;
  615.     return(Close(file));
  616.   }
  617.   return(TRUE);
  618. }
  619. /**/
  620.  
  621.  
  622.  
  623.  
  624.  
  625. /*** pipe function
  626. ***
  627. ***  Creates a pipe.
  628. ***
  629. ***  Inputs: fhs - a pointer to an array of BPTR's where to store
  630. ***             FileHandle's of the writing (element 0) and the
  631. ***             reading end (element 1) of the pipe. These
  632. ***             filehandles may be used for calls of Read(), Write()
  633. ***             Close() or ReadASync().
  634. ***          mode - one of MODE_NEWFILE or MODE_READWRITE, which will
  635. ***             be used to create the writing end of the pipe
  636. ***
  637. ***  Result: TRUE for sucess, FALSE otherwise; you are guaranteed,
  638. ***     that no files are open in the latter case.
  639. **/
  640. int pipe(BPTR *fhs, ULONG mode)
  641.  
  642. { struct MsgPort *oldconsoletask;
  643.   int result = FALSE;
  644.  
  645.   oldconsoletask = SetConsoleTask(&handlerProcess->pr_MsgPort);
  646.  
  647.   fhs[0] = fhs[1] = (BPTR) NULL;
  648.  
  649.   if ((fhs[0] = Open((STRPTR) "CONSOLE:", mode)))
  650.   { if ((fhs[1] = Open((STRPTR) "CONSOLE:", MODE_OLDFILE)))
  651.     { result = TRUE;
  652.     }
  653.     else
  654.     { pipeClose(fhs[0]);
  655.       fhs[0] = (BPTR) NULL;
  656.     }
  657.   }
  658.  
  659.   SetConsoleTask(oldconsoletask);
  660.   return(result);
  661. }
  662. /**/
  663.  
  664.  
  665.  
  666.  
  667.  
  668.  
  669. /*** Child communication section
  670. **/
  671. #define CPUser 1
  672. #define CPProc 2
  673. #define CPLoop 3
  674.  
  675. typedef int CPKind;
  676.  
  677. typedef struct {
  678.     struct MinNode node;
  679.     CPKind kind;
  680.     BPTR from[2], to[2];
  681.     BPTR msgFileHandle;
  682.     STRPTR name;
  683.     struct Process *proc;
  684. } ChildProc;
  685.  
  686. void InterruptChildProcess(ProcRef pr)
  687.  
  688. { ChildProc *cp = pr;
  689.  
  690.   if (cp->proc)
  691.   { Signal((struct Task *) cp->proc, SIGBREAKF_CTRL_C);
  692.   }
  693. }
  694.  
  695. void DestroyChildProcess(ProcRef pr)
  696.  
  697. { ChildProc *cp;
  698.  
  699.   for (cp = (ChildProc *) childProcessList.mlh_Head;
  700.        cp->node.mln_Succ;
  701.        cp = (ChildProc *) cp->node.mln_Succ)
  702.   { if ((cp == (ChildProc *) pr))
  703.     { int error;
  704.  
  705.       OutputToProcess(cp, "quit\n", 5, &error);
  706.       pipeClose(cp->to[0]);
  707.       pipeClose(cp->from[0]);
  708.       pipeClose(cp->from[1]);
  709.       pipeClose(cp->to[1]);
  710.       Remove((struct Node *) cp);
  711.       if (cp->name)
  712.       { free(cp->name);
  713.       }
  714.       free(cp);
  715.     }
  716.   }
  717. }
  718.  
  719.  
  720.  
  721.  
  722.  
  723. /**
  724. ***  This function starts a child process.
  725. ***
  726. ***  Inputs: cmdLine - the command to execute; first word will be
  727. ***             treated as binary to load, rest of line will be used
  728. ***             as arguments
  729. ***          pr - pointer where to store a process reference
  730. ***
  731. ***  Result: 0, if successful, error number otherwise
  732. **/
  733. int StartChildProcess(char *cmdLine, ProcRef *pr)
  734.  
  735. { ChildProc *cp;
  736.   int error = ENOMEM;
  737.  
  738.   if (appData.debugMode)
  739.   { fprintf(debugFP, "Starting child process \"%s\".\n", cmdLine);
  740.   }
  741.  
  742.   if ((cp = malloc(sizeof(*cp))))
  743.   { AddTail((struct List *) &childProcessList, (struct Node *) cp);
  744.     cp->kind = CPProc;
  745.     cp->from[0] = cp->from[1] = (BPTR) NULL;
  746.     cp->to[0] = cp->to[1] = (BPTR) NULL;
  747.     cp->name = NULL;
  748.     cp->proc = NULL;
  749.  
  750.     if ((pipe(cp->from, MODE_READWRITE)))
  751.     { if ((pipe(cp->to, MODE_NEWFILE)))
  752.       { cp->msgFileHandle = ((struct FileHandle *) BADDR(cp->from[0]))->fh_Arg1;
  753.  
  754.     if ((cp->name = (STRPTR) strdup(cmdLine)))
  755.     { BPTR lock;
  756.       STRPTR args, name;
  757.  
  758.       /*
  759.           Let name point to the command name and args to the
  760.           arguments.
  761.       */
  762.       name = cp->name;
  763.       while (isspace(*name))
  764.       { name++;
  765.       }
  766.  
  767.       if (*name == '"')
  768.       { name++;
  769.         if ((args = (STRPTR) strchr((char *) name, '"')))
  770.         { *args++ = '\0';
  771.         }
  772.         else
  773.         { args = (STRPTR) "";
  774.         }
  775.       }
  776.       else
  777.       { args = name;
  778.         while (*args  &&  !isspace(*args))
  779.         { ++args;
  780.         }
  781.         if (*args)
  782.         { *args++ = '\0';
  783.         }
  784.       }
  785.  
  786.       if ((lock = Lock(name, SHARED_LOCK)))
  787.       { BPTR parentLock;
  788.  
  789.         parentLock = ParentDir(lock);
  790.         UnLock(lock);
  791.  
  792.         if (parentLock)
  793.         { BPTR segList;
  794.  
  795.           if ((segList = NewLoadSeg(name, NULL)))
  796.           { cp->proc = CreateNewProcTags(
  797.                 NP_Seglist, segList,
  798.                 NP_Input, cp->to[1],
  799.                 NP_Output, cp->from[0],
  800.                 NP_StackSize, amigaAppData.childStack,
  801.                 NP_Name, FilePart(cp->name),
  802.                 NP_Priority, amigaAppData.childPriority,
  803.                 NP_HomeDir, parentLock,
  804.                 NP_CopyVars, FALSE,
  805.                 NP_Cli, TRUE,
  806.                 NP_CommandName, name,
  807.                 NP_Arguments, args,
  808.                 TAG_DONE);
  809.         if (cp->proc)
  810.         {
  811. #ifdef DEBUG_HANDLER
  812.           kprintf("Childprocess `%s' created.\n", cmdLine);
  813. #endif
  814.           cp->from[0] = (BPTR) NULL;
  815.           cp->to[1] = (BPTR) NULL;
  816.           *pr = cp;
  817.           return(0);
  818.         }
  819.         UnLoadSeg(segList);
  820.           }
  821.           UnLock(parentLock);
  822.         }
  823.       }
  824.       else
  825.       { error = ENOENT;
  826.       }
  827.     }
  828.       }
  829.     }
  830.   }
  831.  
  832.   DestroyChildProcess(cp);
  833.   *pr = NULL;
  834.   return(error);
  835. }
  836.  
  837. int OpenLoopback(ProcRef *pr)
  838.  
  839. { ChildProc *cp;
  840.   int error = 0;
  841.  
  842.   if ((cp = malloc(sizeof(*cp))))
  843.   { cp->kind = CPLoop;
  844.     cp->from[0] = cp->from[1] = (BPTR) NULL;
  845.     cp->to[0] = cp->to[1] = (BPTR) NULL;
  846.  
  847.     if (pipe(cp->to, MODE_READWRITE))
  848.     { cp->msgFileHandle = cp->to[0];
  849.       cp->from[1] = cp->to[1];
  850.       cp->to[1] = (BPTR) NULL;
  851.     }
  852.     else
  853.     { error = ENOMEM;
  854.     }
  855.   }
  856.   else
  857.   { error = ENOMEM;
  858.   }
  859.  
  860.   return(error);
  861. }
  862. /**/
  863.  
  864.  
  865.  
  866.  
  867.  
  868. /**
  869. ***  Child process functions
  870. **/
  871. int OpenTelnet(char *host, char* port, ProcRef *pr)
  872.  
  873. { char cmdLine[MSG_SIZ];
  874.  
  875.   sprintf(cmdLine, "%s %s %s", appData.telnetProgram, host, port);
  876.   return(StartChildProcess(cmdLine, pr));
  877. }
  878.  
  879. int OpenTCP(char *host, char* port, ProcRef *pr)
  880.  
  881. { DisplayFatalError("Socket support is not configured in.", 0, 2);
  882.   return(ENOENT);
  883. }
  884.  
  885. int OpenCommPort(char *name, ProcRef *pr)
  886.  
  887. { DisplayFatalError("Serial line support is not configured in.", 0, 2);
  888.   return(ENOENT);
  889. }
  890.  
  891. int OpenRcmd(char *host, char *user, char *cmd, ProcRef *pr)
  892.  
  893. { DisplayFatalError("Internal rcmd not implemented.", 0, 10);
  894.   return(-1);
  895. }
  896. /**/
  897.  
  898.  
  899.  
  900. /*** Input source section
  901. */
  902. #define INPUT_SOURCE_BUF_SIZE 4096
  903.  
  904. typedef struct
  905. { struct MinNode node;
  906.   CPKind kind;
  907.   int lineByLine;
  908.   InputCallback func;
  909.   ChildProc *cp;
  910.   struct MsgPort *mp;
  911.   LONG cis_Arg1;
  912.   FILE *fp;
  913.   struct MsgPort *cisPort;
  914.   struct DosPacket *dp;
  915.   BOOL dpsent;
  916.   char buf[INPUT_SOURCE_BUF_SIZE];
  917. } InputSource;
  918.  
  919. void DoInputCallback(ULONG receivedsigs)
  920.  
  921. { struct Message *msg;
  922.   struct DosPacket *dp;
  923.   InputSource *is;
  924.  
  925.   if (receivedsigs & (1 << pipesPort->mp_SigBit))
  926.   { while((msg = GetMsg(pipesPort)))
  927.     { dp = (struct DosPacket *) msg->mn_Node.ln_Name;
  928.  
  929.       switch (dp->dp_Type)
  930.       { case ACTION_END:
  931.     case ACTION_WRITE:
  932.       for (is = (InputSource *) inputSourceList.mlh_Head;
  933.            dp  &&  is->node.mln_Succ;
  934.            is = (InputSource *) is->node.mln_Succ)
  935.       { if (is->kind == CPProc  &&  is->cp->msgFileHandle == dp->dp_Arg1)
  936.         { if (dp->dp_Type == ACTION_END)
  937.           {
  938. #ifdef DEBUG_HANDLER
  939.         kprintf("DoInputCallback: ACTION_END, Arg1 = %ld.\n"
  940.             "                 Telling frontend and sending to handler.\n",
  941.             dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3);
  942. #endif
  943.         PutMsg(&handlerProcess->pr_MsgPort, msg);
  944.         (is->func)((InputSourceRef) is, is->buf, 0, 0);
  945.           }
  946.           else
  947.           { int len = dp->dp_Arg3;
  948.  
  949.         memcpy(is->buf, (char *) dp->dp_Arg2, len);
  950.         is->buf[len] = NULLCHAR;
  951. #ifdef DEBUG_HANDLER
  952.         kprintf("DoInputCallback: ACTION_WRITE, Arg1 = %ld, Arg2 = %ld, Arg3 = %ld.\n"
  953.             "                 Replying okay. ",
  954.             dp->dp_Type, dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3);
  955.         kprints((char *) dp->dp_Arg2, dp->dp_Arg3);
  956. #endif
  957.         ReplyPkt(dp, len, 0);
  958.         (is->func)((InputSourceRef) is, is->buf, len, 0);
  959.           }
  960.           dp = NULL;
  961.           break;
  962.         }
  963.       }
  964.       if (dp)
  965.       {
  966. #ifdef DEBUG_HANDLER
  967.         if (dp->dp_Type == ACTION_END)
  968.         { kprintf("DoInputCallback: ACTION_END, Arg1 = %ld.\n"
  969.               "                 Sending to handler.\n",
  970.               dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3);
  971.         }
  972.         else
  973.         { kprintf("DoInputCallback: Type = %ld, Arg1 = %ld, Arg2 = %ld, Arg3 = %ld.\n"
  974.               "                 Pipe unknown, replying okay. ",
  975.               dp->dp_Type, dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3);
  976.           kprints((char *) dp->dp_Arg2, dp->dp_Arg3);
  977.         }
  978. #endif
  979.         PutMsg(&handlerProcess->pr_MsgPort, msg);
  980.       }
  981.       break;
  982.  
  983.     default:
  984.       /**
  985.       ***  This is for the handler, redirect it.
  986.       **/
  987. #ifdef DEBUG_HANDLER
  988.       kprintf("DoInputCallback: Type = %ld, Arg1 = %ld, Arg2 = %ld, Arg3 = %ld.\n"
  989.           "                 Redirecting to handler.\n",
  990.           dp->dp_Type, dp->dp_Arg1, dp->dp_Arg2, dp->dp_Arg3);
  991. #endif
  992.       PutMsg(&handlerProcess->pr_MsgPort, msg);
  993.       break;
  994.       }
  995.  
  996.     }
  997.   }
  998.  
  999.   for (is = (InputSource *) inputSourceList.mlh_Head;
  1000.        is->node.mln_Succ;
  1001.        is = (InputSource *) is->node.mln_Succ)
  1002.   { if (is->kind == CPUser  &&  (receivedsigs & (1 << is->mp->mp_SigBit)))
  1003.     { msg = GetMsg(is->mp);
  1004.       dp = (struct DosPacket *) msg->mn_Node.ln_Name;
  1005.       if (dp == is->dp)
  1006.       { is->dpsent = FALSE;
  1007.     if (dp->dp_Res1 > 0)
  1008.     { is->buf[dp->dp_Res1] = '\0';
  1009.     }
  1010. #ifdef DEBUG_HANDLER
  1011.     kprintf("DoInputCallback: ICS Input ");
  1012.     kprints((char *) dp->dp_Arg2, dp->dp_Res1);
  1013. #endif
  1014.     (is->func)((InputSourceRef) is, is->buf, dp->dp_Res1, 0);
  1015.     dp->dp_Type = ACTION_READ;
  1016.     dp->dp_Arg1 = is->cis_Arg1;
  1017.     dp->dp_Arg2 = (ULONG) is->buf;
  1018.     dp->dp_Arg3 = sizeof(is->buf)-1;
  1019.     SendPkt(dp, is->cisPort, is->mp);
  1020.     is->dpsent = TRUE;
  1021.       }
  1022.     }
  1023.   }
  1024. }
  1025.  
  1026.  
  1027. InputSourceRef AddInputSource(ProcRef pr, int lineByLine, InputCallback func)
  1028.  
  1029. { InputSource *is;
  1030.   ChildProc *cp = (ChildProc *) pr;
  1031.   ULONG success = FALSE;;
  1032.  
  1033.   if ((is = (InputSource *) malloc(sizeof(*is))))
  1034.   { AddTail((struct List *) &inputSourceList, (struct Node *) is);
  1035.     is->lineByLine = lineByLine;
  1036.     is->func = func;
  1037.     is->cp = cp;
  1038.     is->fp = NULL;
  1039.     is->dp = NULL;
  1040.     is->mp = NULL;
  1041.     if (pr != NoProc)
  1042.     { is->kind = cp->kind;
  1043.       success = TRUE;
  1044.     }
  1045.     else
  1046.     { ULONG windowOpen = FALSE;
  1047.  
  1048.       /**
  1049.       ***  Open a window, if required.
  1050.       **/
  1051.       if (amigaAppData.icsWindow  ||  !Input()  ||  !Output())
  1052.       { char *winName;
  1053.     BPTR cos;
  1054.  
  1055.     if (!(winName = (char *) amigaAppData.icsWindow))
  1056.     { winName = "CON:////ICS";
  1057.     }
  1058.  
  1059.     if ((is->fp = toUserFP = fopen(winName, "r+")))
  1060.     { if ((cos = (BPTR) fdtofh(fileno(toUserFP))))
  1061.       { is->cis_Arg1 = ((struct FileHandle *) BADDR(cos))->fh_Arg1;
  1062.         is->cisPort = ((struct FileHandle *) BADDR(cos))->fh_Type;
  1063.         windowOpen = TRUE;
  1064.       }
  1065.     }
  1066.     if (!windowOpen)
  1067.     { DisplayFatalError("Can't open window %s.\nOut of memory?", 0, 10);
  1068.     }
  1069.       }
  1070.       else
  1071.       { is->cis_Arg1 = ((struct FileHandle *) BADDR(Input()))->fh_Arg1;
  1072.     is->cisPort = ((struct FileHandle *) BADDR(Input()))->fh_Type;
  1073.     windowOpen = TRUE;
  1074.       }
  1075.  
  1076.       if (windowOpen)
  1077.       { is->kind = CPUser;
  1078.     is->dpsent = FALSE;
  1079.     if ((is->dp = AllocDosObject(DOS_STDPKT, NULL)))
  1080.     { if ((is->mp = CreateMsgPort()))
  1081.       { is->dp->dp_Type = ACTION_READ;
  1082.         is->dp->dp_Arg1 = is->cis_Arg1;
  1083.         is->dp->dp_Arg2 = (ULONG) is->buf;
  1084.         is->dp->dp_Arg3 = sizeof(is->buf) - 1;
  1085.         SendPkt(is->dp, is->cisPort, is->mp);
  1086.         is->dpsent = TRUE;
  1087.         success = TRUE;
  1088.         pipeSignals |= (1 << is->mp->mp_SigBit);
  1089.       }
  1090.     }
  1091.       }
  1092.     }
  1093.   }
  1094.  
  1095.   if (!success)
  1096.   { RemoveInputSource(is);
  1097.     is = NULL;
  1098.   }
  1099.  
  1100.   return(is);
  1101. }
  1102.  
  1103. void RemoveInputSource(InputSourceRef isr)
  1104.  
  1105. { InputSource *is;
  1106.  
  1107.   for (is = (InputSource *) inputSourceList.mlh_Head;
  1108.        is->node.mln_Succ;
  1109.        is = (InputSource *) is->node.mln_Succ)
  1110.   { if (is == isr)
  1111.     { if (is->kind == CPUser)
  1112.       { if (is->dpsent)
  1113.     { DoPkt3(is->cisPort, ACTION_STACK, is->cis_Arg1, (ULONG) "\n", 1);
  1114.       AbortPkt(is->cisPort, is->dp);
  1115.       WaitPort(is->mp);
  1116.       GetMsg(is->mp);
  1117.     }
  1118.     if (is->mp)
  1119.     { pipeSignals &= ~(1 << is->mp->mp_SigBit);
  1120.       DeleteMsgPort(is->mp);
  1121.     }
  1122.     if (is->dp)
  1123.     { FreeDosObject(DOS_STDPKT, is->dp);
  1124.     }
  1125.     if (is->fp)
  1126.     { fclose(is->fp);
  1127.     }
  1128.       }
  1129.       else if (is->kind == CPProc)
  1130.       { DestroyChildProcess(is->cp);
  1131.       }
  1132.  
  1133.       Remove((struct Node *) is);
  1134.       free(is);
  1135.       break;
  1136.     }
  1137.   }
  1138. }
  1139.  
  1140. int OutputToProcess(ProcRef pr, char *message, int count, int *outError)
  1141.  
  1142. { ChildProc *cp;
  1143.   int outCount;
  1144.  
  1145.   for (cp = (ChildProc *) childProcessList.mlh_Head;
  1146.        cp->node.mln_Succ;
  1147.        cp = (ChildProc *) cp->node.mln_Succ)
  1148.   { if (cp == (ChildProc *) pr)
  1149.     { if ((outCount = Write(cp->to[0], message, count))  ==  count)
  1150.       { *outError = 0;
  1151.       }
  1152.       else
  1153.       { *outError = ENOMEM;
  1154.       }
  1155.       return(outCount);
  1156.     }
  1157.   }
  1158.   *outError = ENOENT;
  1159.   return(0);
  1160. }
  1161. /**/
  1162.  
  1163.  
  1164.  
  1165.  
  1166. /*** popen function
  1167. ***
  1168. ***  *Very* simple replacement
  1169. **/
  1170. FILE *popen(const char *cmdLine, const char *mode)
  1171.  
  1172. { char buf[L_tmpnam+5];
  1173.   FILE *fp = NULL;
  1174.   BPTR fileHandle;
  1175.   int error = ENOENT;
  1176.  
  1177.   strcpy(buf, "PIPE:");
  1178.   tmpnam(buf+5);
  1179.  
  1180.   if ((fileHandle = Open((STRPTR) buf, MODE_NEWFILE)))
  1181.   { if ((fp = fopen(buf, "r")))
  1182.     { if (!SystemTags((STRPTR) cmdLine, SYS_Output, fileHandle))
  1183.       { error = 0;
  1184.       }
  1185.       else
  1186.       { fclose(fp);
  1187.     fp = NULL;
  1188.       }
  1189.     }
  1190.     Close(fileHandle);
  1191.   }
  1192.  
  1193.   errno = error;
  1194.   return(fp);
  1195. }
  1196.  
  1197. int pclose(FILE *fp)
  1198.  
  1199. { if (fp)
  1200.   { return(fclose(fp));
  1201.   }
  1202.   return(0);
  1203. }
  1204. /**/
  1205.  
  1206.  
  1207.  
  1208.  
  1209.  
  1210. /*** PipesClose function
  1211. ***
  1212. ***  Terminates the handler process by sending him
  1213. ***  an ACTION_DIE packet and waiting for the reply.
  1214. ***  (This guarantees, that the child process
  1215. ***  terminates first.
  1216. **/
  1217. VOID PipesClose(VOID)
  1218.  
  1219. { ChildProc *cp;
  1220.   InputSource *is;
  1221.  
  1222.   while ((is = (InputSource *) inputSourceList.mlh_Head)->node.mln_Succ)
  1223.   { RemoveInputSource((InputSourceRef) is);
  1224.   }
  1225.  
  1226.   while ((cp = (ChildProc *) childProcessList.mlh_Head)->node.mln_Succ)
  1227.   { DestroyChildProcess((ProcRef) cp);
  1228.   }
  1229.  
  1230.   if (handlerProcess)
  1231.   { pipesPacket->dp_Type = ACTION_DIE;
  1232.     SendPkt(pipesPacket, &handlerProcess->pr_MsgPort, pipesPort);
  1233.   }
  1234.  
  1235.   if (pipesPort)
  1236.   { ULONG childProcessRunning = TRUE;
  1237.  
  1238.     while (childProcessRunning)
  1239.     { struct Message *message;
  1240.  
  1241.       WaitPort(pipesPort);
  1242.       while ((message = GetMsg(pipesPort)))
  1243.       { struct DosPacket *dosPacket = (struct DosPacket *) message->mn_Node.ln_Name;
  1244.  
  1245.     switch (dosPacket->dp_Type)
  1246.     { case ACTION_DIE:
  1247.         childProcessRunning = FALSE;
  1248.         break;
  1249.       case ACTION_WRITE:
  1250. #ifdef DEBUG_HANDLER
  1251.         kprintf("PipesClose: Type = %ld, Arg1 = %ld, Arg2 = %ld, Arg3 = %ld.\n"
  1252.             "            Replying okay. ",
  1253.             dosPacket->dp_Type, dosPacket->dp_Arg1, dosPacket->dp_Arg2, dosPacket->dp_Arg3);
  1254.         kprints((char *) dosPacket->dp_Arg2, dosPacket->dp_Arg3);
  1255. #endif
  1256.         ReplyPkt(dosPacket, dosPacket->dp_Arg3, 0);
  1257.         break;
  1258.       default:
  1259. #ifdef DEBUG_HANDLER
  1260.         kprintf("PipesClose: Type = %ld, Arg1 = %ld, Arg2 = %ld, Arg3 = %ld.\n"
  1261.             "            Redirecting to handler.\n",
  1262.             dosPacket->dp_Type, dosPacket->dp_Arg1, dosPacket->dp_Arg2, dosPacket->dp_Arg3);
  1263. #endif
  1264.         PutMsg(&handlerProcess->pr_MsgPort, message);
  1265.         break;
  1266.     }
  1267.       }
  1268.     }
  1269.     DeleteMsgPort(pipesPort);
  1270.   }
  1271.  
  1272.   if (pipesPool)
  1273.   { LibDeletePool(pipesPool);
  1274.   }
  1275.  
  1276.   if (pipesPacket)
  1277.   { FreeDosObject(DOS_STDPKT, pipesPacket);
  1278.   }
  1279. }
  1280. /**/
  1281.  
  1282.  
  1283.  
  1284.  
  1285.  
  1286. /*** PpipesInit function
  1287. ***
  1288. ***  Initialize the handler.
  1289. **/
  1290. VOID PipesInit(VOID)
  1291.  
  1292. { NewList((struct List *) &inputSourceList);
  1293.   NewList((struct List *) &childProcessList);
  1294.  
  1295.   /**
  1296.   ***  Allocate a dos packet
  1297.   **/
  1298.   if ((pipesPacket = AllocDosObject(DOS_STDPKT, NULL)))
  1299.   { if ((pipesPort = CreateMsgPort()))
  1300.     { pipeSignals = (1 << pipesPort->mp_SigBit);
  1301.       if ((pipesPool = LibCreatePool(MEMF_ANY, 4096, 2048)))
  1302.       { if ((handlerProcess = CreateNewProcTags(NP_Entry, xboardPipesHandler,
  1303.                         NP_Name, "AmyBoard pipe handler",
  1304.                         NP_CopyVars, FALSE,
  1305.                         TAG_DONE)))
  1306.     { return;
  1307.     }
  1308.       }
  1309.  
  1310.       DeleteMsgPort(pipesPort);
  1311.       pipesPort = NULL;
  1312.     }
  1313.   }
  1314.   exit(10);
  1315. }
  1316. /**/
  1317.